package com.zuorenke.vertx.handler;

import com.zuorenke.help.*;
import com.zuorenke.model.constants.CasCsts;
import com.zuorenke.model.constants.Constants;
import com.zuorenke.model.Performer;
import com.zuorenke.serialize.support.json.JsonUtils;
import com.zuorenke.vertx.WebRouteMapping;
import com.zuorenke.vertx.anno.Order;
import com.zuorenke.vertx.anno.RequestBody;
import com.zuorenke.vertx.anno.RequestHeader;
import com.zuorenke.vertx.anno.RequestMethod;
import com.zuorenke.vertx.standard.PreHandler;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.json.DecodeException;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.FileUpload;
import io.vertx.ext.web.RoutingContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import scala.annotation.meta.param;

import javax.annotation.Resource;
import javax.xml.bind.ValidationException;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author Z.R.K
 * @description
 * @create 2019-05-14 10:28:17
 **/
@Component
@Order(900)
@Slf4j
public class RequestServicePreHandler implements PreHandler<RoutingContext> {
	@Resource
	private WebRouteMapping webRouteMapping;
	
	@Override
	public void handle(RoutingContext event) {
		HttpServerRequest request = event.request();
		String path = request.path();
		HttpMethod method = request.method();
		Set<FileUpload> fileUploads = event.fileUploads();
		for (FileUpload upload : fileUploads) {
			// fileName: 乐课网依赖关系.vsd
			// name: data
			// uploadedFileName : file-uploads\88bf6207-b8a5-4415-bfcb-a8265eb619b4
			// contentType: application/vnd.visio
			log.info("fileName: {} , name: {}, uploadedFileName : {}, contentType: {}  "
					, upload.fileName(), upload.name(), upload.uploadedFileName(), upload.contentType());
		}
		Performer performer = webRouteMapping.get(path, method);
		event.put(Constants.ROUTE_PERFORMER, performer);
		if (!MyCollectionUtils.isEmpty(performer.getParamTypes())) {
			try{
				event.put(Constants.ROUTE_PARAMS, buildParams(performer, event));
			}catch(ValidationException e){
				ResponseUtils.response500Msg(event.response(), e.getMessage());
				return;
			}
		}
		HandlerUtils.next(event);
	}
	
	private Object[] buildParams(Performer performer, RoutingContext ctx) throws ValidationException {
		HttpServerRequest request = ctx.request();
		List<Class> paramClasses = performer.getParamClasses();
		List<Type> paramTypes = performer.getParamTypes();
		List<String> paramNames = performer.getParamNames();
		List<Annotation[]> paramAnnos = performer.getParamAnnos();
		if (MyCollectionUtils.isEmpty(paramClasses)) {
			return new Object[0];
		}
		int length = paramClasses.size();
		Object[] params = new Object[length];
		String jsonStr = null;
		if (ctx.get(HttpHeaders.CONTENT_LENGTH.toString()) != null) {
			jsonStr = ctx.getBodyAsString();
		}
		
		for (int i = 0; i < length; i++) {
			String paramName = paramNames.get(i);
			if(CasCsts.TICKET.equals(paramName)){
				params[i] = ctx.get(CasCsts.TICKET);
				continue;
			}
			Class clazz = paramClasses.get(i);
			Annotation[] annos = paramAnnos.get(i);
			try{
				for (Annotation anno : annos) {
					if (RequestBody.class.equals(anno.annotationType())) {
						if(Map.class.equals(clazz)){
							ParameterizedType type = (ParameterizedType)paramTypes.get(i);
							Type[] types = type.getActualTypeArguments();
							params[i] = JsonUtils.readMap(jsonStr, (Class)types[0], (Class)types[1]);
						}else if(List.class.equals(clazz)){
							ParameterizedType type = (ParameterizedType)paramTypes.get(i);
							Type[] types = type.getActualTypeArguments();
							params[i] = JsonUtils.readList(jsonStr, (Class)types[0]);
						}else if (jsonStr != null && String.class.equals(clazz)) {
							params[i] = jsonStr;
						}else if (jsonStr != null) {
							params[i] = JsonUtils.fromJson(jsonStr, clazz);
						}
					} else if (RequestHeader.class.equals(anno.annotationType())) {
						params[i] = request.getHeader(paramName);
					}
				}
				if(params[i] == null){
					if(HttpMethod.class.equals(clazz)){
						params[i] = request.method();
					}
				}
				if (params[i] == null) {
					params[i] = request.getParam(paramName);
				}
				if (params[i] != null) {
					if(Integer.class.equals(clazz) || int.class.equals(clazz)){
						params[i] = Integer.parseInt(params[i].toString());
					}else if(Long.class.equals(clazz) || long.class.equals(clazz)){
						params[i] = Long.parseLong(params[i].toString());
					}else if(Date.class.equals(clazz)){
						SimpleDateFormat sdf = new SimpleDateFormat(SimpleFormatString.DATETIME_FORMAT);
						params[i] = sdf.parse(params[i].toString());
					}else if(Boolean.class.equals(clazz) || boolean.class.equals(clazz)){
						params[i] = Boolean.valueOf(params[i].toString());
					}
				} else {
					if (int.class.equals(clazz)) {
						params[i] = 0;
					} else if (long.class.equals(clazz)) {
						params[i] = 0L;
					} else if (boolean.class.equals(clazz)) {
						params[i] = false;
					}
				}
			}catch(Exception e){
				e.printStackTrace();
				throw new ValidationException(clazz.getSimpleName() + "-" + paramName + "参数异常!");
			}
		}
		return params;
	}
}
